package jco3.core;

import com.alibaba.fastjson.JSONObject;
import com.sap.conn.jco.JCoContext;
import com.sap.conn.jco.JCoDestination;
import com.sap.conn.jco.JCoException;
import com.sap.conn.jco.JCoField;
import com.sap.conn.jco.JCoFieldIterator;
import com.sap.conn.jco.JCoFunction;
import com.sap.conn.jco.JCoParameterList;
import com.sap.conn.jco.JCoRecordField;
import com.sap.conn.jco.JCoRecordFieldIterator;
import com.sap.conn.jco.JCoRepository;
import com.sap.conn.jco.JCoRuntimeException;
import com.sap.conn.jco.JCoTable;

import jco3.core.annotation.RfcName;
import jco3.core.comkit.ConfigKit;

import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RFC{
	
	private String rfcName = "";
	private JCoDestination destination = null;
	private JCoFunction function = null;
	private int processInstanceId = 0;
	public SapProxy proxy = null;
	
	private JCoParameterList importList = null;
	private JCoParameterList exportList = null;
	
	public int getProcessInstanceId(){
		return this.processInstanceId;
	}
	public void setProcessInstanceId(int processInstanceId) {
		this.processInstanceId = processInstanceId;
	}

	public void setImportList(JCoParameterList importList){
		this.importList = importList;
	}
	public void init() {
	}
	
	public String getPnFile(String pnname) {
		if(ConfigKit.isDev()) {
			return "test-"+pnname;
		}
		return pnname;
	}
	
	public RFC(){
		String pn = "sap";
		this.destination = SapJcoStore.getDestination(getPnFile(pn));
		if(getClass().isAnnotationPresent(RfcName.class)) {
			RfcName rfc = (RfcName)getClass().getAnnotation(RfcName.class);
			this.rfcName = rfc.value();
		}else {
			String classname = getClass().getName();
			this.rfcName = classname.substring(classname.lastIndexOf(".")+1);
		}
		
		try {
			this.function = SapHelper.getRfcFunction(this.rfcName, this.destination);
			this.importList = this.function.getImportParameterList();
		} catch (Exception e) {
			e.printStackTrace();
		}
		init();
	}
	
	public RFC(String rfcName) {
		String pn = "sap";
		this.destination = SapJcoStore.getDestination(getPnFile(pn));
		this.rfcName = rfcName;
		try {
			this.function = SapHelper.getRfcFunction(rfcName, this.destination);
			this.importList = this.function.getImportParameterList();
		} catch (Exception e) {
			e.printStackTrace();
		}
		init();
	}
	
	public RFC(String poolName,String rfcName) {
		String pn = poolName;
		this.destination = SapJcoStore.getDestination(getPnFile(pn));
		this.rfcName = rfcName;
		try {
			this.function = SapHelper.getRfcFunction(rfcName, this.destination);
			this.importList = this.function.getImportParameterList();
		} catch (Exception e) {
			e.printStackTrace();
		}
		init();
	}
	
	public JSONObject jcoFunctionMeta2Json() {
		return RfcUtils.jcoFunctionMeta2Json(getFunction());
	}
	
	public JSONObject getTable2Json(String tableName) {
		return RfcUtils.jcoTableMeta2Json(getTable(tableName));
	}
	
	public JCoParameterList getImportList() {
		return this.importList;
	}
	
	public JCoFunction getFunction() {
		return this.function;
	}
	
	public JCoTable getTable(String key) {
		return this.function.getTableParameterList().getTable(key);
	}
	
	public void setImportValue(Map<String, Object> values) {
		if(values == null) {
			return;
		}
		for(String key:values.keySet()) {
			setImportValue(key,formatValue(this.importList.getFieldIterator(), key, values.get(key)));
		}
	}
	
	public void setImportValue(String key,Object value) {
		try {
			this.importList.setValue(key, formatValue(this.importList.getFieldIterator(), key, value));
		} catch (JCoRuntimeException e) {
			if(e.toString().indexOf("JCO_ERROR_FIELD_NOT_FOUND")==-1) {
				throw e;
			}
		}
	}
	
	
	public Object formatValue(JCoFieldIterator fit,String key,Object value) {
		if(fit == null) {
			return value;
		}
		try {
			do {
				JCoField field = fit.nextField();
				String fieldName = field.getName();
				String fieldType = field.getTypeAsString();
				int len = field.getLength();
				if(fieldName.equals(key) && ("CHAR".equals(fieldType)) && (value.toString().length()<len)) {
					return formatZero((String) value, len);
				}
			} while (fit.hasNextField());
		} catch (Exception e) {
			e.printStackTrace();
		}
		return value;
	}
	
	
	public static String formatZero(String in,int len) {
		if(!isNumeric(in)) {
			return in;
		}
		int strLen = in.length();
		if(strLen<len) {
			while(strLen<len){
				StringBuffer sb= new StringBuffer();
				sb.append("0").append(in);
				in = sb.toString();
				strLen = in.length();
			}
		}
		return in;
	}
	
	public static boolean isNumeric(String str) {
		Pattern pattern = Pattern.compile("[0-9]*");
		return pattern.matcher(str).matches();
	}
	
	public void excute() throws Exception{
		this.function = fillData(this.function);
		if(this.proxy == null) {
			this.proxy = new SapProxy(this);
		}
		SapExecutor exec = new SapExecutor(this.proxy);
		this.function = (JCoFunction)exec.processSap(this.destination, this.function);
		this.exportList = this.function.getExportParameterList();
	}
	
	public static JCoFunction fillData(JCoFunction jcoFunc) {
		return jcoFunc;
	}
	
	public List<Map<String, Object>> table2List(JCoTable table) {
	    List list = new ArrayList();
	    if ((table == null) || (table.getNumRows() <= 0)) {
	      return list;
	    }
	    int rows = table.getNumRows();
	    if (rows <= 0) return list;
	    for (int i = 0; i < rows; i++) {
	      table.setRow(i);
	      JCoRecordFieldIterator it = table.getRecordFieldIterator();
	      Map map = new HashMap();
	      while (it.hasNextField()) {
	        JCoRecordField field = it.nextRecordField();
	        String fieldName = field.getName();

	        Object value = field.getValue();
	        DateFormat jcoDateFormat = new SimpleDateFormat("yyyy-MM-dd");
	        DateFormat jcoTimeFormat = new SimpleDateFormat("HH:mm:ss");
	        if (value == null)
	          value = "";
	        else {
	          switch (field.getType()) {
	          case 1:
	            value = jcoDateFormat.format(value);
	            break;
	          case 3:
	            value = jcoTimeFormat.format(value);
	          case 2:
	          }

	        }

	        map.put(fieldName, value);
	      }
	      list.add(map);
	    }

	    return list;
	}

}